package com.hyh.sso.helper;

import com.alibaba.fastjson.JSON;
import com.hyh.redis.helper.RedisHelper;
import com.hyh.sso.LoginStatus;
import com.hyh.sso.po.LoginResult;
import com.hyh.sso.po.LoginUser;
import com.hyh.sso.po.UserToken;
import com.hyh.sso.service.LoginService;
import com.hyh.utils.common.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 登录助手
 *
 * @Author: heyuhua
 * @Date: 2021/1/8 17:13
 */
@Component
public class LoginHelper {

    /**
     * 日志
     */
    private static final Logger LOG = LoggerFactory.getLogger(LoginHelper.class);

    /**
     * 登录用户信息KEY
     */
    private final String LOGIN_USER_KEY = "login:user:";
    /**
     * 登录用户TOKEN KEY
     */
    private final String LOGIN_TOKEN_KEY = "login:token:";
    /**
     * 登录失败统计 KEY
     */
    private final String LOGIN_FAIL_COUNT_KEY = "login:fail:count";
    /**
     * 登录失败最多允许次数
     */
    private final long MAX_FAIL_COUNT = 5;


    /**
     * 登录服务
     */
    @Resource
    private LoginService loginService;

    /**
     * redis助手
     */
    @Autowired
    private RedisHelper redisHelper;


    /**
     * 登录
     *
     * @param account     用户名
     * @param password    密码
     * @param callbackUrl 回调URL
     * @return
     */
    public LoginResult login(String account, String password, String callbackUrl) {
        Assert.notNull(account, "account is null ");
        Assert.notNull(password, "password is null ");
        Assert.notNull(callbackUrl, "callbackUrl is null ");
        //判断账户是否多次登录失败被锁定
        String value = redisHelper.getStringValue(LOGIN_FAIL_COUNT_KEY + account);
        if (StringUtils.isNotBlank(value)) {
            Long loginFailCount = Long.parseLong(value);
            if (loginFailCount.longValue() >= MAX_FAIL_COUNT) {
                return new LoginResult(LoginStatus.ACCOUNT_LOCK);
            }
        }
        //登录操作
        LoginResult loginResult = loginService.login(account, password, callbackUrl);
        switch (loginResult.getLoginStatus()) {
            case SUCCESS:
                //登录成功
                loginSuccess(loginResult);
                break;
            case FAIL:
                //登录失败
                loginFail(loginResult);
                break;
            case ERROR:
                loginError(loginResult);
                //登录异常
                break;
            default:
                break;
        }
        return loginResult;
    }

    /**
     * 注销
     *
     * @param account
     * @param token
     */
    public void logout(String account, String token) {
        Assert.notNull(account, "account is null ");
        Assert.notNull(token, "token is null ");
        removeKey(account, token);
    }

    /**
     * 注销
     *
     * @param token
     */
    public void logout(String token) {
        Assert.notNull(token, "token is null ");
        removeKey(token);
    }

    /**
     * 获取登录用户
     *
     * @param token
     * @return
     */
    public LoginUser getLoginUser(String token) {
        Assert.notNull(token, "token is null ");
        String value = redisHelper.getStringValue(LOGIN_USER_KEY + token);
        if (StringUtils.isNotBlank(value)) {
            return JSON.parseObject(value, LoginUser.class);
        }
        return null;
    }

    /**
     * 移除 key
     *
     * @param account
     * @param token
     */
    private void removeKey(String account, String token) {
        redisHelper.del(LOGIN_FAIL_COUNT_KEY + account);
        redisHelper.del(LOGIN_TOKEN_KEY + account);
        redisHelper.del(LOGIN_USER_KEY + token);
    }

    /**
     * 移除 Key
     *
     * @param token
     */
    private void removeKey(String token) {
        redisHelper.del(LOGIN_USER_KEY + token);
        //其余的key到达过期时间自动过期
    }


    /**
     * 登录异常
     *
     * @param loginResult
     */
    private void loginError(LoginResult loginResult) {
        LOG.error("user 【" + loginResult.getLoginUser().getAccount() + "】 login error");
    }

    /**
     * 登录失败操作
     *
     * @param loginResult
     */
    private void loginFail(LoginResult loginResult) {
        String key = LOGIN_FAIL_COUNT_KEY + loginResult.getLoginUser();
        redisHelper.increment(key, 30 * 60 * 1000);
    }

    /**
     * 登录成功操作
     *
     * @param loginResult
     */
    private void loginSuccess(LoginResult loginResult) {
        LoginUser loginUser = loginResult.getLoginUser();
        loginUser.setLoginTime(String.valueOf(new Date().getTime()));
        UserToken userToken = UserToken.getUserToken();
        redisHelper.set(LOGIN_TOKEN_KEY + loginResult.getLoginUser().getAccount(), JSON.toJSONString(userToken), 30, TimeUnit.MINUTES);
        redisHelper.set(LOGIN_USER_KEY + userToken.getToken(), JSON.toJSONString(loginUser), 30, TimeUnit.MINUTES);
        redisHelper.del(LOGIN_FAIL_COUNT_KEY + loginResult.getLoginUser());
    }


}
